﻿using Newtonsoft.Json.Linq;
using OpenTK.Mathematics;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using System.Xml.Linq;
using ttbit.core;
using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;

namespace spriteeditor.WorkingSpace
{
    public class WorkingSpace
    {
        public bool IsOpen
        {
            get
            {
                return playerList != null;
            }
        }
        public string WorkingPath
        {
            get;
            private set;
        }
        public void Open(string path)
        {
            WorkingPath = path;
            playerList = new PlayerList();
            spriteList = new SpriteList();


            var playerconfig = System.IO.Path.Combine(path, "allplayers.json");

            if (System.IO.File.Exists(playerconfig))
            {
                var file = System.IO.File.ReadAllText(playerconfig);
                var json = Newtonsoft.Json.Linq.JArray.Parse(file);
                playerList.LoadFromJson(path, json);
            }
            var spriteconfig = System.IO.Path.Combine(path, "allsprites.json");
            if (System.IO.File.Exists(spriteconfig))
            {
                var file = System.IO.File.ReadAllText(spriteconfig);
                var json = Newtonsoft.Json.Linq.JArray.Parse(file);
                spriteList.LoadFromJson(json);
            }

            //刷新所有文件，找出有没有新加入的文件

            List<string> listfilename = new List<string>();
            if (spriteList.Sprites != null)
            {
                foreach (var item in spriteList.Sprites)
                {
                    var filename = System.IO.Path.GetFileName(item.filename).ToLower();
                    if (listfilename.Contains(filename) == false)
                        listfilename.Add(filename);
                }
            }
            //load all pngs;
            realTextures = new Dictionary<string, Texture>();
            shorttexname = new Dictionary<string, string>();
            packtexname = new Dictionary<string, string>();
            newtexname = new Dictionary<string, string>();
            var allpng = System.IO.Directory.GetFiles(path, "*.png", SearchOption.AllDirectories);
            foreach (var png in allpng)
            {
                var key = System.IO.Path.GetFileName(png).ToLower();
                if (listfilename.Contains(key) == false)
                {
                    newtexname[key] = png;
                }
                else
                {
                    if (path.Contains("_packed"))
                        packtexname[key] = png;
                    else
                        shorttexname[key] = png;
                }
            }
        }
        public void Save()
        {
            var playerconfig = System.IO.Path.Combine(WorkingPath, "allplayers.json");
            var spriteconfig = System.IO.Path.Combine(WorkingPath, "allsprites.json");
            var jarray = playerList.ToJson(WorkingPath);
            System.IO.File.Delete(playerconfig);
            System.IO.File.WriteAllText(playerconfig, jarray.ToString(), Encoding.UTF8);
            var jarray2 = spriteList.ToJson();
            System.IO.File.Delete(spriteconfig);
            System.IO.File.WriteAllText(spriteconfig, jarray2.ToString(), Encoding.UTF8);
        }
        public byte[] LoadRGBA(string name, out int width, out int height)
        {
            var lname = name.ToLower();

            string realfile = null;
            if (shorttexname.TryGetValue(lname, out var texfilename))
            {
                realfile = texfilename;
            }
            if (packtexname.TryGetValue(lname, out var packfilename))
            {
                realfile = packfilename;
            }
            if (newtexname.TryGetValue(lname, out var newfilename))
            {
                realfile = newfilename;
            }
            if (realfile != null)
            {
                using (var fs = System.IO.File.OpenRead(realfile))
                {
                    var t = CoreLoadTool.LoadTextureData_RGBA(fs, out width, out height);

                    return t;
                }
            }
            width = 0;
            height = 0;
            return null;
        }
        public Texture GetTexture(string name)
        {
            var lname = name.ToLower();
            if (realTextures.TryGetValue(lname, out var tex))
            {
                return tex;
            }
            string realfile = null;
            if (shorttexname.TryGetValue(lname, out var texfilename))
            {
                realfile = texfilename;
            }
            if (packtexname.TryGetValue(lname, out var packfilename))
            {
                realfile = packfilename;
            }
            if (newtexname.TryGetValue(lname, out var newfilename))
            {
                realfile = newfilename;
            }
            if (realfile != null)
            {
                using (var fs = System.IO.File.OpenRead(realfile))
                {
                    var t = CoreLoadTool.LoadTextureData_RGBA(fs, out int w, out int h);
                    var ntex = new Texture((ushort)w, (ushort)h, ttbit.IGL.TextureType.RGBA_32, t);
                    realTextures[lname] = ntex;
                    return ntex;
                }
            }

            return null;
        }
        public Dictionary<string, string> shorttexname;
        public Dictionary<string, string> packtexname;
        public Dictionary<string, string> newtexname;


        Dictionary<string, Texture> realTextures;
        public PlayerList playerList;
        public SpriteList spriteList;


        public int usermode;//mode1 showsprite
        public List<SkinSprite> usermode_showlist;
        public float usermode_scale = 1.0f;
        public bool usermode_crossfront = false;
        public NodeTag_Sprite usermode_editsprite = null;
        public void ConvertWildTex2Sprite(string name, string playername, string partname)
        {
            if (!this.newtexname.Remove(name, out string _filename))
            {
                MessageBox.Show("error no tex:" + name);
                return;
            }
            this.shorttexname[name] = _filename;
            var skinSprite = new SkinSprite();
            skinSprite.name = System.IO.Path.GetFileNameWithoutExtension(name);
            skinSprite.filename = name;
            skinSprite.playername = playername;
            skinSprite.part_name = partname;
            skinSprite.part_skin = "";
            skinSprite.part_id = "";//autogen
            skinSprite.povit = Point.Empty;
            var texdata = this.LoadRGBA(name, out int w, out int h);
            GetBorder(texdata, w, h, out var x, out var y, out var x2, out var y2);
            skinSprite.uv = new Rectangle(x, y, x2 - x + 1, y2 - y + 1);
            skinSprite.povit.X = (x2-x)/2;
            skinSprite.povit.Y = (y2-y)*3/4 ;
            this.spriteList.Sprites.Add(skinSprite);

        }
        public void GetBorder(byte[] data, int w, int h, out int x, out int y, out int x2, out int y2)
        {
            x = int.MaxValue;
            x2 = int.MinValue;
            y = int.MaxValue;
            y2 = int.MinValue;
            for (var _y = 0; _y < h; _y++)
            {
                for (var _x = 0; _x < w; _x++)
                {
                    var seekr = (_y * w + _x) * 4 + 3;
                    var alpha = (int)(((float)data[seekr] / 255.0) * 7);//小于1/7 视为透明
                    if (alpha > 0)
                    {
                        if (x > _x) x = _x;
                        if (x2 < _x) x2 = _x;
                        if (y > _y) y = _y;
                        if (y2 < _y) y2 = _y;
                    }
                }
            }
        }

    }
    public class SkinSprite
    {

        public string name;     //精灵名
        public string filename; //精灵所在的文件名

        public string resgroup; //打包的时候分到哪个贴图里

        public string playername;   //归属于哪个角色，也可以不归属
        public string part_name;    //兼容部位名，换装用
        public string part_skin;    //换装皮肤名
        public string part_id;      //部位id，换装用
        
        public Rectangle uv;    //UV
        public Point povit;//轴  //轴
    }
    public class SpriteList
    {
        public List<SkinSprite> Sprites = new List<SkinSprite>();
        public void LoadFromJson(JArray json)
        {
            Sprites = new List<SkinSprite>();
            foreach (JObject item in json)
            {
                SkinSprite s = new SkinSprite();
                s.filename = item["filename"].ToString();
                s.name = item["name"].ToString();
                if (item.ContainsKey("resgroup"))
                    s.resgroup = item["resgroup"].ToString();
                if (item.ContainsKey("playername"))
                    s.playername = item["playername"].ToString();
                if (item.ContainsKey("part_name"))
                    s.part_name = item["part_name"].ToString();
                if (item.ContainsKey("part_skin"))
                    s.part_skin = item["part_skin"].ToString();
                if (item.ContainsKey("part_id"))
                    s.part_id = item["part_id"].ToString();

                s.uv.X = (int)item["X"];
                s.uv.Y = (int)item["Y"];
                s.uv.Width = (int)item["Width"];
                s.uv.Height = (int)item["Height"];
                s.povit.X = (int)item["Povit_X"];
                s.povit.Y = (int)item["Povit_Y"];
                Sprites.Add(s);
            }
        }
        public JArray ToJson()
        {
            JArray jArray = new JArray();
            foreach (var s in Sprites)
            {
                JObject json = new JObject();
                json["filename"] = s.filename;
                json["resgroup"] = s.resgroup;
                json["name"] = s.name;
                json["playername"] = s.playername;
                json["part_name"] = s.part_name;
                json["part_skin"] = s.part_skin;
                json["part_id"] = s.part_id;
                json["X"] = s.uv.X;
                json["Y"] = s.uv.Y;
                json["Width"] = s.uv.Width;
                json["Height"] = s.uv.Height;
                json["Povit_X"] = s.povit.X;
                json["Povit_Y"] = s.povit.Y;
                jArray.Add(json);
            }
            return jArray;
        }
        public List<SkinSprite> Find(string name)
        {
            List<SkinSprite> sprites = new List<SkinSprite>();
            foreach (var s in this.Sprites)
            {
                if (s.name.ToLower() == name.ToLower())
                    sprites.Add(s);
            }
            return sprites;
        }
        public List<SkinSprite> FindByPlayer(string player)
        {
            List<SkinSprite> sprites = new List<SkinSprite>();
            foreach (var s in this.Sprites)
            {
                if (s.playername.ToLower() == player.ToLower())
                    sprites.Add(s);
            }
            return sprites;
        }
        public List<SkinSprite> FindByPart(string part)
        {
            List<SkinSprite> sprites = new List<SkinSprite>();
            foreach (var s in this.Sprites)
            {
                if (s.part_name.ToLower() == part.ToLower())
                    sprites.Add(s);
            }
            return sprites;
        }
        public List<SkinSprite> FindByPlayerAndPart(string player, string part)
        {
            List<SkinSprite> sprites = new List<SkinSprite>();
            foreach (var s in this.Sprites)
            {
                if (s.playername.ToLower() == player.ToLower() && s.part_name == part.ToLower())
                    sprites.Add(s);
            }
            return sprites;
        }
    }
    //表示一个身体部位
    public class Part
    {
        public string name;//可以没有
        public string partid;
    }

    /// <summary>
    /// 表示显示的Rect
    /// </summary>
    public class ShowRect
    {
        public Part part;
        public Vector2 pos;
    }
    /// <summary>
    /// 表示功能的Rect
    /// </summary>
    public class FuncRect
    {
        public string tag;
        public Rectangle rect;
    }
    public class Frame
    {
        public bool key;
        public ShowRect[] showrects;
        public FuncRect[] funcrects;
    }
    public class Ani
    {
        public string Name;
        public int fps;
        public Frame[] frames;
    }
    public class Player
    {
        public string Name;
        public string[] Parts;
        public Ani[] Animations;
        public static Player FromJson(JObject json)
        {
            return null;
        }
        public JObject ToJson()
        {
            return null;
        }
    }
    public class PlayerList
    {
        public Dictionary<string, Player> allPlayers = new Dictionary<string, Player>();
        public void LoadFromJson(string playerpath, JArray json)
        {
            allPlayers = new Dictionary<string, Player>();
            foreach (JObject item in json)
            {
                var name = item["name"].ToString();
                var config = item["config"].ToString();
                var playerPath = System.IO.Path.Combine(playerpath, config);
                var playerjson = JObject.Parse(System.IO.File.ReadAllText(playerPath));
                allPlayers[name] = Player.FromJson(playerjson);
            }
        }
        public JArray ToJson(string playerpath)
        {
            JArray json = new JArray();
            foreach (var player in allPlayers)
            {
                JObject item = new JObject();
                item["name"] = player.Key;
                var config = player.Value.Name + ".player.json";
                item["value"] = config;
                var playerjsonfile = System.IO.Path.Combine(playerpath, config);
                System.IO.File.Delete(playerjsonfile);
                System.IO.File.WriteAllText(playerjsonfile, player.Value.ToJson().ToString(), Encoding.UTF8);
                json.Add(item);
            }
            return json;
        }
        public Player GetPlayer(string key)
        {
            return allPlayers[key];
        }
    }

}
